blob: 0f1194c12b754a4085452a3a926275611f13ca16 [file] [log] [blame]
{{/*
* Copyright 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/}}
{{Include "../api/templates/vulkan_common.tmpl"}}
{{Global "clang-format" (Strings "clang-format" "-style=file")}}
{{Macro "DefineGlobals" $}}
{{$ | Macro "dispatch_gen.h" | Format (Global "clang-format") | Write "dispatch_gen.h" }}
{{$ | Macro "dispatch_gen.cpp" | Format (Global "clang-format") | Write "dispatch_gen.cpp"}}
{{/*
-------------------------------------------------------------------------------
dispatch_gen.h
-------------------------------------------------------------------------------
*/}}
{{define "dispatch_gen.h"}}
/*
•* Copyright 2015 The Android Open Source Project
•*
•* Licensed under the Apache License, Version 2.0 (the "License");
•* you may not use this file except in compliance with the License.
•* You may obtain a copy of the License at
•*
•* http://www.apache.org/licenses/LICENSE-2.0
•*
•* Unless required by applicable law or agreed to in writing, software
•* distributed under the License is distributed on an "AS IS" BASIS,
•* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
•* See the License for the specific language governing permissions and
•* limitations under the License.
•*/
#define VK_USE_PLATFORM_ANDROID_KHR
#include <vulkan/vk_android_native_buffer.h>
#include <vulkan/vk_ext_debug_report.h>
#include <vulkan/vulkan.h>
namespace vulkan {
struct InstanceDispatchTable
// clang-format off
{{range $f := AllCommands $}}
{{if (Macro "IsInstanceDispatched" $f)}}
{{Macro "FunctionPtrName" $f}} {{Macro "BaseName" $f}};
{{end}}
{{end}}
// clang-format on
»};
struct DeviceDispatchTable
// clang-format off
{{range $f := AllCommands $}}
{{if (Macro "IsDeviceDispatched" $f)}}
{{Macro "FunctionPtrName" $f}} {{Macro "BaseName" $f}};
{{end}}
{{end}}
// clang-format on
»};
struct DriverDispatchTable
// clang-format off
{{range $f := AllCommands $}}
{{if (Macro "IsInstanceDispatched" $f)}}
{{if not (Macro "IsLoaderFunction" $f)}}
{{Macro "FunctionPtrName" $f}} {{Macro "BaseName" $f}};
{{end}}
{{end}}
{{end}}
PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
{{/* TODO(jessehall): Needed by swapchain code. Figure out a better way of
handling this that avoids the special case. Probably should rework
things so the driver dispatch table has all driver functions. Probably
need separate instance- and device-level copies, fill in all device-
dispatched functions in the device-level copies only, and change
GetDeviceProcAddr_Bottom to look in the already-loaded driver
dispatch table rather than forwarding to the driver's
vkGetDeviceProcAddr. */}}
PFN_vkCreateImage CreateImage;
PFN_vkDestroyImage DestroyImage;
PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
PFN_vkAcquireImageANDROID AcquireImageANDROID;
PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
// clang-format on
»};
} // namespace vulkan
¶{{end}}
{{/*
-------------------------------------------------------------------------------
dispatch_gen.cpp
-------------------------------------------------------------------------------
*/}}
{{define "dispatch_gen.cpp"}}
/*
•* Copyright 2015 The Android Open Source Project
•*
•* Licensed under the Apache License, Version 2.0 (the "License");
•* you may not use this file except in compliance with the License.
•* You may obtain a copy of the License at
•*
•* http://www.apache.org/licenses/LICENSE-2.0
•*
•* Unless required by applicable law or agreed to in writing, software
•* distributed under the License is distributed on an "AS IS" BASIS,
•* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
•* See the License for the specific language governing permissions and
•* limitations under the License.
•*/
#include <log/log.h>
#include <algorithm>
#include "loader.h"
#define UNLIKELY(expr) __builtin_expect((expr), 0)
using namespace vulkan;
namespace {
struct NameProc {
const char* name;
PFN_vkVoidFunction proc;
};
PFN_vkVoidFunction Lookup(const char* name, const NameProc* begin, const NameProc* end) {
const auto& entry = std::lower_bound(
begin, end, name,
[](const NameProc& e, const char* n) { return strcmp(e.name, n) < 0; });
if (entry == end || strcmp(entry->name, name) != 0)
return nullptr;
return entry->proc;
}
template <size_t N>
PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) {
return Lookup(name, procs, procs + N);
}
const NameProc kLoaderExportProcs[] =
// clang-format off
{{range $f := SortBy (AllCommands $) "FunctionName"}}
{{if (Macro "IsExported" $f)}}
{"{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>({{$f.Name}})},
{{end}}
{{end}}
// clang-format on
»};
const NameProc kLoaderGlobalProcs[] =
// clang-format off
{{range $f := SortBy (AllCommands $) "FunctionName"}}
{{if and (Macro "HasLoaderTopImpl" $f) (eq (Macro "Vtbl" $f) "Global")}}
{"{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>(§
static_cast<{{Macro "FunctionPtrName" $f}}>(§
{{Macro "BaseName" $f}}_Top))},
{{end}}
{{end}}
// clang-format on
»};
const NameProc kLoaderTopProcs[] =
// clang-format off
{{range $f := SortBy (AllCommands $) "FunctionName"}}
{{if (Macro "HasLoaderTopImpl" $f)}}
{"{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>(§
static_cast<{{Macro "FunctionPtrName" $f}}>(§
{{Macro "BaseName" $f}}_Top))},
{{end}}
{{end}}
// clang-format on
»};
const NameProc kLoaderBottomProcs[] =
// clang-format off
{{range $f := SortBy (AllCommands $) "FunctionName"}}
{{if (Macro "HasLoaderBottomImpl" $f)}}
{"{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>(§
static_cast<{{Macro "FunctionPtrName" $f}}>(§
{{Macro "BaseName" $f}}_Bottom))},
{{end}}
{{end}}
// clang-format on
»};
struct NameOffset {
const char* name;
size_t offset;
};
ssize_t Lookup(const char* name,
const NameOffset* begin,
const NameOffset* end) {
const auto& entry = std::lower_bound(
begin, end, name, [](const NameOffset& e, const char* n) {
return strcmp(e.name, n) < 0;
});
if (entry == end || strcmp(entry->name, name) != 0)
return -1;
return static_cast<ssize_t>(entry->offset);
}
template <size_t N, class Table>
PFN_vkVoidFunction Lookup(const char* name,
const NameOffset (&offsets)[N],
const Table& table) {
ssize_t offset = Lookup(name, offsets, offsets + N);
if (offset < 0)
return nullptr;
uintptr_t base = reinterpret_cast<uintptr_t>(&table);
return *reinterpret_cast<PFN_vkVoidFunction*>(base +
static_cast<size_t>(offset));
}
const NameOffset kInstanceDispatchOffsets[] =
// clang-format off
{{range $f := SortBy (AllCommands $) "FunctionName"}}
{{if (Macro "IsInstanceDispatched" $f)}}
{"{{$f.Name}}", offsetof(InstanceDispatchTable, {{Macro "BaseName" $f}})},
{{end}}
{{end}}
// clang-format on
»};
const NameOffset kDeviceDispatchOffsets[] =
// clang-format off
{{range $f := SortBy (AllCommands $) "FunctionName"}}
{{if (Macro "IsDeviceDispatched" $f)}}
{"{{$f.Name}}", offsetof(DeviceDispatchTable, {{Macro "BaseName" $f}})},
{{end}}
{{end}}
// clang-format on
»};
} // anonymous namespace
namespace vulkan {
PFN_vkVoidFunction GetLoaderExportProcAddr(const char* name) {
return Lookup(name, kLoaderExportProcs);
}
PFN_vkVoidFunction GetLoaderGlobalProcAddr(const char* name) {
return Lookup(name, kLoaderGlobalProcs);
}
PFN_vkVoidFunction GetLoaderTopProcAddr(const char* name) {
return Lookup(name, kLoaderTopProcs);
}
PFN_vkVoidFunction GetLoaderBottomProcAddr(const char* name) {
return Lookup(name, kLoaderBottomProcs);
}
PFN_vkVoidFunction GetDispatchProcAddr(const InstanceDispatchTable& dispatch,
const char* name) {
return Lookup(name, kInstanceDispatchOffsets, dispatch);
}
PFN_vkVoidFunction GetDispatchProcAddr(const DeviceDispatchTable& dispatch,
const char* name) {
return Lookup(name, kDeviceDispatchOffsets, dispatch);
}
bool LoadInstanceDispatchTable(VkInstance instance,
PFN_vkGetInstanceProcAddr get_proc_addr,
InstanceDispatchTable& dispatch)
bool success = true;
// clang-format off
{{range $f := AllCommands $}}
{{if (Macro "IsInstanceDispatched" $f)}}
dispatch.{{Macro "BaseName" $f}} = §
reinterpret_cast<{{Macro "FunctionPtrName" $f}}>(§
get_proc_addr(instance, "{{$f.Name}}"));
if (UNLIKELY(!dispatch.{{Macro "BaseName" $f}})) {
ALOGE("missing instance proc: %s", "{{$f.Name}}");
success = false;
}
{{end}}
{{end}}
// clang-format on
return success;
»}
bool LoadDeviceDispatchTable(VkDevice device,
PFN_vkGetDeviceProcAddr get_proc_addr,
DeviceDispatchTable& dispatch)
bool success = true;
// clang-format off
{{range $f := AllCommands $}}
{{if (Macro "IsDeviceDispatched" $f)}}
dispatch.{{Macro "BaseName" $f}} = §
reinterpret_cast<{{Macro "FunctionPtrName" $f}}>(§
get_proc_addr(device, "{{$f.Name}}"));
if (UNLIKELY(!dispatch.{{Macro "BaseName" $f}})) {
ALOGE("missing device proc: %s", "{{$f.Name}}");
success = false;
}
{{end}}
{{end}}
// clang-format on
return success;
»}
bool LoadDriverDispatchTable(VkInstance instance,
PFN_vkGetInstanceProcAddr get_proc_addr,
const InstanceExtensionSet& extensions,
DriverDispatchTable& dispatch)
bool success = true;
// clang-format off
{{range $f := AllCommands $}}
{{if (Macro "IsInstanceDispatched" $f)}}
{{if not (Macro "IsLoaderFunction" $f)}}
{{$ext := GetAnnotation $f "extension"}}
{{if $ext}}
if (extensions[{{Macro "ExtensionConstant" $ext}}]) {
{{end}}
dispatch.{{Macro "BaseName" $f}} = §
reinterpret_cast<{{Macro "FunctionPtrName" $f}}>(§
get_proc_addr(instance, "{{$f.Name}}"));
if (UNLIKELY(!dispatch.{{Macro "BaseName" $f}})) {
ALOGE("missing driver proc: %s", "{{$f.Name}}");
success = false;
}
{{if $ext}}
}
{{end}}
{{end}}
{{end}}
{{end}}
dispatch.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(get_proc_addr(instance, "vkGetDeviceProcAddr"));
if (UNLIKELY(!dispatch.GetDeviceProcAddr)) {
ALOGE("missing driver proc: %s", "vkGetDeviceProcAddr");
success = false;
}
dispatch.CreateImage = reinterpret_cast<PFN_vkCreateImage>(get_proc_addr(instance, "vkCreateImage"));
if (UNLIKELY(!dispatch.CreateImage)) {
ALOGE("missing driver proc: %s", "vkCreateImage");
success = false;
}
dispatch.DestroyImage = reinterpret_cast<PFN_vkDestroyImage>(get_proc_addr(instance, "vkDestroyImage"));
if (UNLIKELY(!dispatch.DestroyImage)) {
ALOGE("missing driver proc: %s", "vkDestroyImage");
success = false;
}
dispatch.GetSwapchainGrallocUsageANDROID = reinterpret_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(get_proc_addr(instance, "vkGetSwapchainGrallocUsageANDROID"));
if (UNLIKELY(!dispatch.GetSwapchainGrallocUsageANDROID)) {
ALOGE("missing driver proc: %s", "vkGetSwapchainGrallocUsageANDROID");
success = false;
}
dispatch.AcquireImageANDROID = reinterpret_cast<PFN_vkAcquireImageANDROID>(get_proc_addr(instance, "vkAcquireImageANDROID"));
if (UNLIKELY(!dispatch.AcquireImageANDROID)) {
ALOGE("missing driver proc: %s", "vkAcquireImageANDROID");
success = false;
}
dispatch.QueueSignalReleaseImageANDROID = reinterpret_cast<PFN_vkQueueSignalReleaseImageANDROID>(get_proc_addr(instance, "vkQueueSignalReleaseImageANDROID"));
if (UNLIKELY(!dispatch.QueueSignalReleaseImageANDROID)) {
ALOGE("missing driver proc: %s", "vkQueueSignalReleaseImageANDROID");
success = false;
}
// clang-format on
return success;
»}
} // namespace vulkan
// clang-format off
{{range $f := AllCommands $}}
{{if and (not (GetAnnotation $f "pfn")) (Macro "IsExported" $f)}}
__attribute__((visibility("default")))
VKAPI_ATTR {{Node "Type" $f.Return}} {{$f.Name}}({{Macro "Parameters" $f}}) {
{{if not (IsVoid $f.Return.Type)}}return §{{end}}
{{Macro "Dispatch" $f}}({{Macro "Arguments" $f}});
}
{{end}}
{{end}}
// clang-format on
¶{{end}}
{{/*
-------------------------------------------------------------------------------
Emit the dispatch lookup for a function based on its first parameter.
-------------------------------------------------------------------------------
*/}}
{{define "Dispatch"}}
{{AssertType $ "Function"}}
{{if (Macro "HasLoaderTopImpl" $)}}
{{Macro "BaseName" $}}_Top§
{{else}}
{{$p0 := index $.CallParameters 0}}
GetDispatchTable({{$p0.Name}}).{{Macro "BaseName" $}}§
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Map an extension name to InstanceExtension or DeviceExtension enum value
-------------------------------------------------------------------------------
*/}}
{{define "ExtensionConstant"}}
{{$name := index $.Arguments 0}}
{{ if (eq $name "VK_KHR_surface")}}kKHR_surface
{{else if (eq $name "VK_KHR_android_surface")}}kKHR_android_surface
{{else if (eq $name "VK_EXT_debug_report")}}kEXT_debug_report
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a function name without the "vk" prefix.
-------------------------------------------------------------------------------
*/}}
{{define "BaseName"}}
{{AssertType $ "Function"}}
{{TrimPrefix "vk" $.Name}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a comma-separated list of C parameter names for the given command.
-------------------------------------------------------------------------------
*/}}
{{define "Arguments"}}
{{AssertType $ "Function"}}
{{ForEach $.CallParameters "ParameterName" | JoinWith ", "}}
{{end}}
{{/*
------------------------------------------------------------------------------
Emit "true" for supported functions that undergo table dispatch. Only global
functions and functions handled in the loader top without calling into
lower layers are not dispatched.
------------------------------------------------------------------------------
*/}}
{{define "IsInstanceDispatched"}}
{{AssertType $ "Function"}}
{{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Instance")}}
{{if (ne $.Name "vkGetInstanceProcAddr")}}true{{end}}
{{end}}
{{end}}
{{/*
------------------------------------------------------------------------------
Emit "true" for supported functions that can have device-specific dispatch.
------------------------------------------------------------------------------
*/}}
{{define "IsDeviceDispatched"}}
{{AssertType $ "Function"}}
{{if (Macro "IsFunctionSupported" $)}}
{{if eq (Macro "Vtbl" $) "Device"}}
{{if ne $.Name "vkGetDeviceProcAddr"}}
true
{{end}}
{{end}}
{{end}}
{{end}}
{{/*
------------------------------------------------------------------------------
Emit "true" if a function is core or from a supportable extension.
------------------------------------------------------------------------------
*/}}
{{define "IsFunctionSupported"}}
{{AssertType $ "Function"}}
{{if not (GetAnnotation $ "pfn")}}
{{$ext := GetAnnotation $ "extension"}}
{{if not $ext}}true
{{else if not (Macro "IsExtensionBlacklisted" $ext)}}true
{{end}}
{{end}}
{{end}}
{{/*
------------------------------------------------------------------------------
Decides whether a function should be exported from the Android Vulkan
library. Functions in the core API and in loader extensions are exported.
------------------------------------------------------------------------------
*/}}
{{define "IsExported"}}
{{AssertType $ "Function"}}
{{if (Macro "IsFunctionSupported" $)}}
{{$ext := GetAnnotation $ "extension"}}
{{if $ext}}
{{Macro "IsLoaderExtension" $ext}}
{{else}}
true
{{end}}
{{end}}
{{end}}
{{/*
------------------------------------------------------------------------------
Reports whether an extension function is implemented entirely by the loader,
and not implemented by drivers.
------------------------------------------------------------------------------
*/}}
{{define "IsLoaderFunction"}}
{{AssertType $ "Function"}}
{{$ext := GetAnnotation $ "extension"}}
{{if $ext}}
{{Macro "IsLoaderExtension" $ext}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emit "true" if the loader has a top-level implementation for the function
that should be called directly rather than dispatching to the first layer.
-------------------------------------------------------------------------------
*/}}
{{define "HasLoaderTopImpl"}}
{{AssertType $ "Function"}}
{{/* Global functions can't be dispatched */}}
{{ if and (not (GetAnnotation $ "pfn")) (eq (Macro "Vtbl" $) "Global")}}true
{{/* G*PA are implemented by reading the dispatch table, not by dispatching
through it. */}}
{{else if eq $.Name "vkGetInstanceProcAddr"}}true
{{else if eq $.Name "vkGetDeviceProcAddr"}}true
{{/* Loader top needs to initialize dispatch for device-level dispatchable
objects */}}
{{else if eq $.Name "vkGetDeviceQueue"}}true
{{else if eq $.Name "vkAllocateCommandBuffers"}}true
{{/* vkDestroy for dispatchable objects needs to handle VK_NULL_HANDLE;
trying to dispatch through that would crash. */}}
{{else if eq $.Name "vkDestroyInstance"}}true
{{else if eq $.Name "vkDestroyDevice"}}true
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emit "true" if the loader has a bottom-level implementation for the function
which terminates the dispatch chain.
-------------------------------------------------------------------------------
*/}}
{{define "HasLoaderBottomImpl"}}
{{AssertType $ "Function"}}
{{if (Macro "IsFunctionSupported" $)}}
{{ if (eq (Macro "Vtbl" $) "Instance")}}true
{{else if (Macro "IsLoaderFunction" $)}}true
{{else if (eq $.Name "vkCreateInstance")}}true
{{else if (eq $.Name "vkGetDeviceProcAddr")}}true
{{end}}
{{end}}
{{end}}
{{/*
------------------------------------------------------------------------------
Emit "true" if an extension is unsupportable on Android.
------------------------------------------------------------------------------
*/}}
{{define "IsExtensionBlacklisted"}}
{{$ext := index $.Arguments 0}}
{{ if eq $ext "VK_KHR_display"}}true
{{else if eq $ext "VK_KHR_display_swapchain"}}true
{{else if eq $ext "VK_KHR_xlib_surface"}}true
{{else if eq $ext "VK_KHR_xcb_surface"}}true
{{else if eq $ext "VK_KHR_wayland_surface"}}true
{{else if eq $ext "VK_KHR_mir_surface"}}true
{{else if eq $ext "VK_KHR_win32_surface"}}true
{{end}}
{{end}}
{{/*
------------------------------------------------------------------------------
Reports whether an extension is implemented entirely by the loader,
so drivers should not enumerate it.
------------------------------------------------------------------------------
*/}}
{{define "IsLoaderExtension"}}
{{$ext := index $.Arguments 0}}
{{ if eq $ext "VK_KHR_surface"}}true
{{else if eq $ext "VK_KHR_swapchain"}}true
{{else if eq $ext "VK_KHR_android_surface"}}true
{{end}}
{{end}}